﻿/*************************************************************************************
 * 文 件 名:   HK_ResetName
 * 
 * 描    述:   该工具中包含了：根据指定字符串查找物体、替换选中物体名称中的指定字符串、对选中物体进行重命名
 * 
 * 版    本：  V1.0
 * 创 建 者：  京产肠饭
 * 创建时间：  2021/8/26
 * 链   接：  https://gitee.com/JingChanChangFan/hk_-unity-tools
*************************************************************************************/

using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;

namespace HKTools
{
    public class HK_ResetName : EditorWindow
    {
        const int ReNameToolPriority = 20;

        //选择了弹出window复选框下的哪个
        int popupIndex = 2;
        string[] popupNameArray = { "Find", "Repalce", "Rename" };
        int[] popupIndexArray = { 0, 1, 2, 3 };

        //方便以后维护,保证上面两个数组顺序和枚举里的顺序对应即可
        enum PopupIndex { Find, Repalce, NewName };

        //查找输入框
        string findInput;
        //替换输入框
        string repalceInput;

        string newNameInput;
        int startIndex;

        static GameObject[] selectedObjs;

        static MethodInfo clearMethod = null;

        [MenuItem("HKTools/ReNameTool(重命名工具)", priority = ReNameToolPriority)]
        static void Init()
        {
            //弹出窗口
            HK_ResetName resetNameWindow = GetWindow<HK_ResetName>("FindOrReplace");
            resetNameWindow.Show();
        }

        void OnGUI()
        {
            EditorGUILayout.Space(15);

            popupIndex = EditorGUILayout.IntPopup("请选择功能:", popupIndex, popupNameArray, popupIndexArray);

            EditorGUILayout.Space();
            //查询
            if (popupIndex == (int)PopupIndex.Find)
            {
                findInput = EditorGUILayout.TextField("查询:", findInput);

                EditorGUILayout.Space();
                //创建一个按钮
                if (GUILayout.Button("查找", GUILayout.Width(55)))
                {
                    Undo.RecordObjects(Selection.objects, "Find");
                    FindOrReplace((int)PopupIndex.Find, findInput, repalceInput);
                }
            }
            //替换
            else if (popupIndex == (int)PopupIndex.Repalce)
            {
                findInput = EditorGUILayout.TextField("查询:", findInput);

                EditorGUILayout.Space();

                repalceInput = EditorGUILayout.TextField("替换为:", repalceInput);

                EditorGUILayout.Space();

                //创建一个按钮
                if (GUILayout.Button("替换", GUILayout.Width(55)))
                {
                    Undo.RecordObjects(Selection.objects, "Replace");
                    FindOrReplace((int)PopupIndex.Repalce, findInput, repalceInput);
                }
            }
            //新命名
            else if (popupIndex == (int)PopupIndex.NewName)
            {
                newNameInput = EditorGUILayout.TextField("重新命名:", newNameInput);

                startIndex = EditorGUILayout.IntField("初始编号：", startIndex);

                EditorGUILayout.Space();

                //创建一个按钮
                if (GUILayout.Button("确定", GUILayout.Width(55)))
                {
                    Undo.RecordObjects(Selection.objects, "Rename");
                    SetNewName(newNameInput);
                }
            }
            Repaint();//实时刷新
        }

        /// <summary>
        /// 查找或替换 
        /// </summary>
        /// <param name="index"></param>0查找 1替换
        /// <param name="findName"></param>查找名字
        /// <param name="replaceName"></param>替换后名字
        void FindOrReplace(int index, string findName, string replaceName)
        {
            ClearConsole();
            //获取所选中物体的数组
            selectedObjs = Selection.gameObjects;
            if (selectedObjs.Length == 0)
            {
                Debug.Log("<color=red>错误: </color>" + "没有选中任何物体!");
                return;
            }
            if (findName == string.Empty || findName == null)
            {
                Debug.Log("<color=red>错误: </color>" + "值不能为空!");
                return;
            }
            if (index == (int)PopupIndex.Repalce)
            {
                if (replaceName == string.Empty || replaceName == null)
                {
                    Debug.Log("<color=red>错误: </color>" + "值不能为空!");
                    return;
                }
            }

            //准备一个存放找到符合查询条件的集合
            List<GameObject> findedObjsArray = new List<GameObject>();
            //遍历是否包含查找的名字
            for (int i = 0; i < selectedObjs.Length; i++)
            {
                if (selectedObjs[i].transform.name.Contains(findName))
                {
                    switch (index)
                    {
                        case (int)PopupIndex.Find:
                            Debug.Log(selectedObjs[i].transform.name);
                            break;
                        case (int)PopupIndex.Repalce:
                            Debug.Log(selectedObjs[i].transform.name + "已替换为:" + "<color=green>" + replaceName + "</color>");
                            selectedObjs[i].transform.name = selectedObjs[i].transform.name.Replace(findName, replaceName);
                            break;
                    }

                    findedObjsArray.Add(selectedObjs[i]);
                }
            }
            Selection.objects = findedObjsArray.ToArray();
        }

        /// <summary>
        /// 全部重命名
        /// </summary>
        /// <param name="newInputName"></param>
        void SetNewName(string newInputName)
        {
            //前期准备工作
            ClearConsole();
            //获取所选中物体的数组
            selectedObjs = Selection.gameObjects;

            if (selectedObjs.Length == 0)
            {
                Debug.Log("<color=red>错误:</color>" + "没有选中任何物体!");
                return;
            }
            if (newInputName == string.Empty || newInputName == null)
            {
                Debug.Log("<color=red>错误:</color>" + "值不能为空!");
                return;
            }

            //遍历
            if (selectedObjs.Length == 1)
            {
                Debug.Log(selectedObjs[0].transform.name + "重命名为:" + "<color=green>" + newInputName + "</color>");
                selectedObjs[0].transform.name = newInputName;
            }
            else if (selectedObjs.Length > 1)
            {
                // 先拆分成一个一个根据父物体名字 分离的list
                Dictionary<string, List<GameObject>> splitedDic = SplitWithParent(selectedObjs);

                //遍历每一个父物体下的list
                foreach (List<GameObject> littleGroup in splitedDic.Values)
                {
                    if (littleGroup.Count == 1)
                    {
                        littleGroup[0].transform.name = newInputName;
                        Debug.Log(littleGroup[0].transform.name + "重命名为:" + "<color=green>" + newInputName + "</color>");
                    }
                    else
                    {
                        //根据下标排序
                        GameObject[] trueSortObjs = SortGameObjs(littleGroup.ToArray());
                        //重命名
                        for (int i = 0; i < trueSortObjs.Length; i++)
                        {
                            Debug.Log(trueSortObjs[i].transform.name + "重命名为:" + "<color=green>" + newInputName + "_" + i + "</color>");
                            trueSortObjs[i].transform.name = newInputName + "_" + (i + startIndex).ToString();
                        }
                    }
                }
            }
        }

        #region 辅助方法
        /// <summary>
        /// 清空log信息
        /// </summary>
        void ClearConsole()
        {
            if (clearMethod == null)
            {
                Type log = typeof(EditorWindow).Assembly.GetType("UnityEditor.LogEntries");
                clearMethod = log.GetMethod("Clear");
            }
            clearMethod.Invoke(null, null);
        }

        /// <summary>
        /// 数组排序 Slection.gameobjects是乱序 在部分时候需要通过下标重新排序
        /// </summary>
        /// <param name="targetObjs"></param>
        /// <returns></returns>
        GameObject[] SortGameObjs(GameObject[] targetObjs)
        {
            GameObject[] sortedObjs = targetObjs;
            GameObject temp;
            for (int i = 0; i < sortedObjs.Length - 1; i++)
            {
                for (int j = 0; j < sortedObjs.Length - i - 1; j++)
                {
                    if (sortedObjs[j].transform.GetSiblingIndex() > sortedObjs[j + 1].transform.GetSiblingIndex())
                    {
                        temp = sortedObjs[j + 1];
                        sortedObjs[j + 1] = sortedObjs[j];
                        sortedObjs[j] = temp;
                    }
                }
            }
            return sortedObjs;
        }

        /// <summary>
        /// 根据传入数组的父物体名字分成更小的几个小组
        /// </summary>
        /// <param name="targetObjs"></param>
        /// <returns></returns>
        Dictionary<string, List<GameObject>> SplitWithParent(GameObject[] targetObjs)
        {
            Dictionary<string, List<GameObject>> splitedDic = new Dictionary<string, List<GameObject>>();

            // 遍历所有选中的物体
            for (int i = 0; i < targetObjs.Length; i++)
            {
                if (targetObjs[i].transform.parent != null)
                {
                    if (!splitedDic.ContainsKey(targetObjs[i].transform.parent.name))
                    {
                        List<GameObject> temp = new List<GameObject>();
                        temp.Add(targetObjs[i]);
                        splitedDic.Add(targetObjs[i].transform.parent.name, temp);
                    }
                    else
                    {
                        splitedDic[targetObjs[i].transform.parent.name].Add(targetObjs[i]);
                    }
                }
                else
                {
                    if (!splitedDic.ContainsKey("NoParent"))
                    {
                        List<GameObject> temp = new List<GameObject>();
                        temp.Add(targetObjs[i]);
                        splitedDic.Add("NoParent", temp);
                    }
                    else
                        splitedDic["NoParent"].Add(targetObjs[i]);
                }
            }

            return splitedDic;
        }
        #endregion
    }
}